// 安全管理器

import { BaseManager } from '../core/BaseManager';
import { RedisClient } from '../core/RedisClient';
import { KeyGenerator } from '../utils/keyGenerator';
import * as crypto from 'crypto';

export interface EncryptionOptions {
  algorithm?: string;
  keyDerivation?: 'pbkdf2' | 'scrypt';
  iterations?: number;
  saltLength?: number;
  ivLength?: number;
}

export interface AccessControlRule {
  id: string;
  pattern: string;
  permissions: ('read' | 'write' | 'delete')[];
  users: string[];
  roles: string[];
  enabled: boolean;
  createdAt: Date;
  expiresAt?: Date;
}

export interface AuditLogEntry {
  id: string;
  timestamp: Date;
  userId: string;
  action: string;
  resource: string;
  result: 'success' | 'failure';
  details?: any;
  ip?: string;
  userAgent?: string;
}

export interface SecurityStats {
  totalEncryptedKeys: number;
  totalAccessRules: number;
  totalAuditLogs: number;
  failedAccessAttempts: number;
  lastAuditCleanup: Date | null;
}

export class SecurityManager extends BaseManager {
  private encryptionKey: Buffer;
  private accessRules: Map<string, AccessControlRule> = new Map();
  private auditLogs: AuditLogEntry[] = [];

  constructor(client: RedisClient, masterKey?: string) {
    super(client, new KeyGenerator({ prefix: 'security' }));

    // 初始化加密密钥
    this.encryptionKey = this.deriveKey(
      masterKey ?? process.env['REDIS_MASTER_KEY'] ?? 'default-key'
    );
  }

  /**
   * 加密数据（简化版本）
   */
  encrypt(data: string, _options: EncryptionOptions = {}): string {
    try {
      // 使用简单的AES加密
      const cipher = crypto.createCipher('aes-256-cbc', this.encryptionKey.toString('hex'));
      let encrypted = cipher.update(data, 'utf8', 'hex');
      encrypted += cipher.final('hex');
      return encrypted;
    } catch (error) {
      throw this.formatError(error, 'Failed to encrypt data');
    }
  }

  /**
   * 解密数据（简化版本）
   */
  decrypt(encryptedData: string, _options: EncryptionOptions = {}): string {
    try {
      // 使用简单的AES解密
      const decipher = crypto.createDecipher('aes-256-cbc', this.encryptionKey.toString('hex'));
      let decrypted = decipher.update(encryptedData, 'hex', 'utf8');
      decrypted += decipher.final('utf8');
      return decrypted;
    } catch (error) {
      throw this.formatError(error, 'Failed to decrypt data');
    }
  }

  /**
   * 安全设置值（加密存储）
   */
  async setSecure(key: string, value: any, ttl?: number): Promise<void> {
    this.validateRequired({ key, value });

    const startTime = this.now();

    try {
      const serializedValue = typeof value === 'string' ? value : JSON.stringify(value);
      const encryptedValue = this.encrypt(serializedValue);

      const secureKey = this.keyGenerator.generate('secure', key);

      if (ttl) {
        await this.setValue(secureKey, encryptedValue, ttl);
      } else {
        await this.setValue(secureKey, encryptedValue);
      }

      this.logMetric('security.set', this.now() - startTime, true, {
        key: key.substring(0, 20),
        encrypted: true,
      });
    } catch (error) {
      this.logMetric('security.set', this.now() - startTime, false, {
        key: key.substring(0, 20),
        error: (error as Error).message,
      });
      throw this.formatError(error, `Failed to set secure value for key: ${key}`);
    }
  }

  /**
   * 安全获取值（解密）
   */
  async getSecure<T = any>(key: string): Promise<T | null> {
    this.validateRequired({ key });

    const startTime = this.now();

    try {
      const secureKey = this.keyGenerator.generate('secure', key);
      const encryptedValue = await this.getValue<string>(secureKey);

      if (!encryptedValue) {
        return null;
      }

      const decryptedValue = this.decrypt(encryptedValue);

      let result: T;
      try {
        result = JSON.parse(decryptedValue);
      } catch {
        result = decryptedValue as T;
      }

      this.logMetric('security.get', this.now() - startTime, true, {
        key: key.substring(0, 20),
        found: true,
      });

      return result;
    } catch (error) {
      this.logMetric('security.get', this.now() - startTime, false, {
        key: key.substring(0, 20),
        error: (error as Error).message,
      });
      throw this.formatError(error, `Failed to get secure value for key: ${key}`);
    }
  }

  /**
   * 添加访问控制规则
   */
  addAccessRule(rule: Omit<AccessControlRule, 'id' | 'createdAt'>): string {
    const id = crypto.randomUUID();
    const accessRule: AccessControlRule = {
      ...rule,
      id,
      createdAt: new Date(),
    };

    this.accessRules.set(id, accessRule);

    this.logger.info(`Access rule added: ${id}`, {
      pattern: rule.pattern,
      permissions: rule.permissions,
      users: rule.users.length,
      roles: rule.roles.length,
    });

    return id;
  }

  /**
   * 移除访问控制规则
   */
  removeAccessRule(id: string): boolean {
    const removed = this.accessRules.delete(id);
    if (removed) {
      this.logger.info(`Access rule removed: ${id}`);
    }
    return removed;
  }

  /**
   * 检查访问权限
   */
  checkAccess(
    userId: string,
    resource: string,
    action: 'read' | 'write' | 'delete',
    userRoles: string[] = []
  ): boolean {
    for (const rule of this.accessRules.values()) {
      if (!rule.enabled) continue;

      // 检查规则是否过期
      if (rule.expiresAt && rule.expiresAt < new Date()) {
        continue;
      }

      // 检查资源模式匹配
      if (!this.matchPattern(resource, rule.pattern)) {
        continue;
      }

      // 检查权限
      if (!rule.permissions.includes(action)) {
        continue;
      }

      // 检查用户或角色
      const hasUserAccess = rule.users.includes(userId);
      const hasRoleAccess = userRoles.some(role => rule.roles.includes(role));

      if (hasUserAccess || hasRoleAccess) {
        this.logAudit({
          userId,
          action: `access_${action}`,
          resource,
          result: 'success',
          details: { ruleId: rule.id },
        });
        return true;
      }
    }

    // 记录访问失败
    this.logAudit({
      userId,
      action: `access_${action}`,
      resource,
      result: 'failure',
      details: { reason: 'access_denied' },
    });

    return false;
  }

  /**
   * 记录审计日志
   */
  logAudit(entry: Omit<AuditLogEntry, 'id' | 'timestamp'>): void {
    const auditEntry: AuditLogEntry = {
      ...entry,
      id: crypto.randomUUID(),
      timestamp: new Date(),
    };

    this.auditLogs.push(auditEntry);

    // 限制内存中的日志数量
    if (this.auditLogs.length > 10000) {
      this.auditLogs = this.auditLogs.slice(-5000);
    }

    this.logger.info('Audit log entry created', {
      userId: entry.userId,
      action: entry.action,
      resource: entry.resource,
      result: entry.result,
    });
  }

  /**
   * 获取审计日志
   */
  getAuditLogs(
    options: {
      userId?: string;
      action?: string;
      result?: 'success' | 'failure';
      startDate?: Date;
      endDate?: Date;
      limit?: number;
    } = {}
  ): AuditLogEntry[] {
    let logs = this.auditLogs;

    // 应用过滤器
    if (options.userId) {
      logs = logs.filter(log => log.userId === options.userId);
    }

    if (options.action) {
      logs = logs.filter(log => log.action === options.action);
    }

    if (options.result) {
      logs = logs.filter(log => log.result === options.result);
    }

    if (options.startDate) {
      logs = logs.filter(log => log.timestamp >= options.startDate!);
    }

    if (options.endDate) {
      logs = logs.filter(log => log.timestamp <= options.endDate!);
    }

    // 按时间倒序排序
    logs.sort((a, b) => b.timestamp.getTime() - a.timestamp.getTime());

    // 应用限制
    if (options.limit) {
      logs = logs.slice(0, options.limit);
    }

    return logs;
  }

  /**
   * 获取安全统计信息
   */
  async getStats(): Promise<SecurityStats> {
    try {
      const secureKeysPattern = this.keyGenerator.generate('secure', '*');
      const secureKeys = await this.getKeys(secureKeysPattern);

      const failedAccessAttempts = this.auditLogs.filter(
        log => log.result === 'failure' && log.action.startsWith('access_')
      ).length;

      return {
        totalEncryptedKeys: secureKeys.length,
        totalAccessRules: this.accessRules.size,
        totalAuditLogs: this.auditLogs.length,
        failedAccessAttempts,
        lastAuditCleanup: null, // 可以添加清理时间跟踪
      };
    } catch (error) {
      throw this.formatError(error, 'Failed to get security stats');
    }
  }

  /**
   * 清理过期的访问规则
   */
  cleanupExpiredRules(): number {
    const now = new Date();
    let removedCount = 0;

    for (const [id, rule] of this.accessRules.entries()) {
      if (rule.expiresAt && rule.expiresAt < now) {
        this.accessRules.delete(id);
        removedCount++;
      }
    }

    if (removedCount > 0) {
      this.logger.info(`Cleaned up ${removedCount} expired access rules`);
    }

    return removedCount;
  }

  /**
   * 派生加密密钥
   */
  private deriveKey(masterKey: string): Buffer {
    return crypto.pbkdf2Sync(masterKey, 'redis-toolkit-salt', 100000, 32, 'sha256');
  }

  /**
   * 模式匹配
   */
  private matchPattern(resource: string, pattern: string): boolean {
    // 简单的通配符匹配实现
    const regexPattern = pattern.replace(/\*/g, '.*').replace(/\?/g, '.');

    const regex = new RegExp(`^${regexPattern}$`);
    return regex.test(resource);
  }
}
